//
//  AudioDecodeViewController.m
//  FFMpegKitDemo
//
//  Created by ilongge on 2023/8/11.
//

#import "AudioDecodeViewController.h"


@interface AudioDecodeViewController ()
{
    AVFormatContext *_formatContext;
    AVCodecContext *_audioCodecContext;
    const struct AVCodec *_audioCodec;
    int _audioStreamIndex;
    AVFrame *_audioFrame;
    NSString *_audioFile;
    dispatch_queue_t _decode_queue;
}
@end

@implementation AudioDecodeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"音频解码";
    _audioFile = @"2023-09-26-16-56-57-10101025.arm";
    _decode_queue = dispatch_queue_create("com.ilongge.queue.audioDecode", DISPATCH_QUEUE_SERIAL);
    [self initCodec];
}
- (void)initCodec
{
    NSString *pathString = [[NSBundle mainBundle] pathForResource:_audioFile ofType:nil];
    if (pathString == nil) {
        NSLog(@"file not exsit");
        return;
    }
    /// 打开音频文件并获取相关上下文
    int ret = avformat_open_input(&_formatContext, pathString.UTF8String, NULL, NULL);
    if (ret != 0) {
        NSLog(@"avformat_open_input : %d", ret);
        return;
    }
    ret = avformat_find_stream_info(_formatContext, NULL);
    if (ret != 0) {
        NSLog(@"avformat_find_stream_info : %d", ret);
        return;
    }
    _audioStreamIndex = -1;
    /// 寻找音频流
    _audioStreamIndex = av_find_best_stream(_formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (_audioStreamIndex < 0) {
        NSLog(@"av_find_best_stream : %d", ret);
        return;
    }
    /// 获取音频流
    AVStream *audioStream = _formatContext->streams[_audioStreamIndex];
    /// 获取并打开解码器
    _audioCodec = avcodec_find_decoder(audioStream->codecpar->codec_id);
    /// 获取解码器上下文
    _audioCodecContext = avcodec_alloc_context3(_audioCodec);
    /// 打开解码器
    ret = avcodec_open2(_audioCodecContext, _audioCodec, NULL);
    if (ret != 0) {
        NSLog(@"avcodec_open2 : %d", ret);
        return;
    }
    /// 申请AVPacket和AVFrame以及相关设置
    _audioFrame = av_frame_alloc();
}
- (IBAction)startDecodeAction:(UIButton *)sender {
    sender.userInteractionEnabled = NO;
    [self audioDecode];
    sender.userInteractionEnabled = YES;
}

- (void)audioDecode
{
    dispatch_async(_decode_queue, ^{
        NSString *pathString = [NSString stringWithFormat:@"%@/Documents/%@_Decode.pcm", NSHomeDirectory(), self->_audioFile];
        [[NSFileManager defaultManager] createFileAtPath:pathString contents:nil attributes:nil];
        NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:pathString];
        NSInteger frameCount = 1;
        AVPacket *packet = av_malloc(sizeof(AVPacket));
        while (true) {
            int ret = av_read_frame(self->_formatContext, packet);
            if (ret == 0) {
                if (packet->stream_index == self->_audioStreamIndex) {
                    ret = avcodec_send_packet(self->_audioCodecContext, packet);
                    av_packet_unref(packet);
                    while (ret >= 0) {
                        ret = avcodec_receive_frame(self->_audioCodecContext, self->_audioFrame);
                        if (ret == AVERROR_EOF) {
                            av_packet_unref(packet);
                            break;
                        }
                        else if (ret == AVERROR(EAGAIN)) {
                            av_packet_unref(packet);
                            break;
                        }
                        else if (ret < 0) {
                            av_frame_unref(self->_audioFrame);
                            break;
                        }
                        else{
                            printf("%5ld 帧 \n", frameCount);
                            int size = av_get_bytes_per_sample(self->_audioFrame->format);
                            NSMutableData *data = [NSMutableData data];
                            for (int index = 0; index < self->_audioFrame->nb_samples; index++) {
                                for (int channel = 0; channel < self->_audioFrame->ch_layout.nb_channels; channel++) {
                                    // 以下代码针对于_audioFrame->data[0]有值且_audioFrame->data[1] = NULL
                                    // 只取_audioFrame->data[0] 每次长度 偏移 _audioFrame->ch_layout.nb_channels
                                    uint8_t * sampleData = self->_audioFrame->data[channel];
                                    if (sampleData) {
                                        NSInteger length = size * self->_audioFrame->ch_layout.nb_channels;
                                        const void * byte = self->_audioFrame->data[channel] + index * length;
                                        [data appendBytes:byte length:length];
                                    }
                                }
                            }
                            [file seekToEndOfFile];
                            [file writeData:data];
                            [file synchronizeFile];
                        }
                    }
                }
                else{
                    av_packet_unref(packet);
                    continue;
                }
            }
            else{
                av_packet_unref(packet);
                break;
            }
            frameCount ++;
        }
        frameCount --;
        av_seek_frame(self->_formatContext, self->_audioStreamIndex, 0, 0);
        [file closeFile];
        av_packet_free(&packet);
    });
}
- (void)dealloc
{
    if (_formatContext != NULL) {
        avformat_close_input(&_formatContext);
    }
    if (_audioCodecContext != NULL) {
        avcodec_free_context(&_audioCodecContext);
    }
    printf("%s\n", __func__);
}
@end
